/*
 * Base.java
 * 
 * Copyright (c) 2007 Aris Bartee
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * Created on Jun 4, 2007, 11:55:29 PM
 * 
 */
package afterburner.jsp;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import afterburner.jsp.fuel.Tank;
import afterburner.jsp.thrust.Textify;

/**
 *
 * @author arisbartee
 */
public class JSP extends Base {

    private String action = "";
    private Tank tank = null;
    public JSP() {
        super();
    }

    /**
     * @see javax.servlet.jsp.HttpJspPage#init(ServletConfig)
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    /**
     * @see javax.servlet.jsp.HttpJspPage#destroy
     */
    @Override
    public void destroy() {
        super.destroy();
    }

    /**
     * @see javax.servlet.jsp.HttpJspPage#service(ServletRequest, ServletResponse)
     */
    public void service(ServletRequest srequest, ServletResponse sresponse) throws ServletException, IOException {
        before(srequest, sresponse);
        execute();

        if (!_response.isCommitted()) {
            if (getLayoutPath() == null) {
                _jspService(_request, _response);
            } else {

                _request.setAttribute("afterburner.outputMap", outputMap);
                ResponseCatcher catcher = new ResponseCatcher(_response);

                _jspService(_request, catcher);
                if(!_response.isCommitted()){
                    outputMap.put("body", catcher.getStringWriter().toString());
                    _request.setAttribute("afterburner.outputMap", outputMap);
                    RequestDispatcher rd = _request.getRequestDispatcher(getLayoutPath());
                    rd.forward(_request, _response);
                }
            }

        }
        after();
    }

    private void before(ServletRequest srequest, ServletResponse sresponse) {
        setRequestResponse(srequest, sresponse);
        outputMap.clear();
        Tank.activateFuel(this);

    }

    private void execute() throws ServletException {


        if (action == null) {
            return;
        }
        try {
            Method method = getClass().getMethod(action, new Class[0]);
            if (method != null) {
                method.invoke(this, new Object[0]);
            }
        } catch (NoSuchMethodException nsme) {
            System.out.println("Didn't find " + action);
        } catch (Exception e) {
            Throwable t = e.getCause();
            if (t == null) {
                t = e;
            }
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            }
            ServletException se = new ServletException(t.getMessage());
            se.setStackTrace(t.getStackTrace());
            throw se;
        }
    }

    private void after() {
        Tank.deActivateFuel(this);
        setRequestResponse(null, null);
        outputMap.clear();
    }

    public void setAction(String action) {
        this.action = action;
    }

    public String getAction() {
        return action;
    }

    /**
     * Makes a keyed piece of content unavailable to the layout template.
     */
    protected void eraseContent(String name) {
        outputMap.remove(name);
    }

    /**
     * Makes content available to the layout template.
     */
    protected void addContent(String name, String content) {
        if (outputMap.containsKey(name)) {

            outputMap.put(name, content + outputMap.get(name));
        } else {
            outputMap.put(name, content);
        }
    }

    /**
     * Set the Layout template to be used
     * @param path_to_layout A URL to a JSP to use a layout template.
     */
    public void setLayoutPath(String path_to_layout) {
        if (path_to_layout != null && (path_to_layout.trim().length() == 0)) {
            this.layoutPath = null;
        } else {
            this.layoutPath = path_to_layout;
        }
    }

    /**
     * Retrieves the path to a JSP to use a layout template.
     */
    public String getLayoutPath() {
        return layoutPath;
    }

    /**
     * Renders a JSP fragment.  It passes the Object the fragment via the request attributes.
     * JSP fragments retrieve the Object using the &gt;jsp:usebean/&lt tag.
     * 
     * @param path_to_fragment Path to a JSP fragment
     * @param pojoName The request attribute key for the Object passed to the fragment
     * @param pojo The object passed the the JSP fragment.
     */
    protected String include(String path_to_fragment, String pojoName, Object pojo) throws ServletException {
        String output = "";
        getRequest().setAttribute(pojoName, pojo);
        output = include(path_to_fragment);
        getRequest().removeAttribute(pojoName);
        return output;
    }

    /**
     * Renders a JSP fragment.  It passes the Object the fragment via the request attributes.
     * JSP fragments retrieve the Object using the &gt;jsp:usebean/&lt> tag.
     */
    protected String include(String path_to_partial) throws ServletException {
        ResponseCatcher catcher = new ResponseCatcher(getResponse());
        RequestDispatcher rd = getRequest().getRequestDispatcher(path_to_partial);
        try {
            rd.include(getRequest(), catcher);
        } catch (Exception ex) {
            ServletException se = new ServletException(ex.getMessage());
            se.setStackTrace(ex.getStackTrace());
            throw se;
        }
        return catcher.getStringWriter().toString();
    }

    /**
     * Escapes html found in the string.
     *
     * @param text  A string to escape.
     * @returns if text is null an empty string is returned.
     */
    protected String html_escape(String text) {
        return Textify.html_escape(text);
    }

    /**
     * Alias for for htm_escape
     * @see html_escape.
     */
    protected String h(String text) {
        return Textify.html_escape(text);
    }

    /**
     * Informs the browser to redirect to a provided url.
     * Short cut method for response.sendRedirect
     */
    protected void redirectTo(String url) throws IOException {
        getResponse().sendRedirect(url);
    }
}
